#include "ArbolSintactico.h"


ArbolSintactico::ArbolSintactico(Nodo* raiz){
	this->raiz=raiz;
}

ArbolSintactico::ArbolSintactico(){
	this->raiz=NULL;
	this->pathYAML="";
	this->nodoActual=NULL;
}


ArbolSintactico::ArbolSintactico(string fichero) {

	this->pathYAML= fichero;

	this->raiz = NULL;

	this->nodoActual = raiz;

}


void ArbolSintactico::setNodoActual(Nodo* actual){

	this->nodoActual=actual;
}

Nodo* ArbolSintactico::getRaiz(){

	return this->raiz;

}





Nodo* ArbolSintactico::buscarNodo(string str){
	Nodo* actual= this->nodoActual;
	Nodo* encontrado=NULL;
	this->buscarRecursivo(actual, encontrado, str);
	return encontrado;
}


void ArbolSintactico::buscarRecursivo(Nodo* nodo,Nodo* &encontrado, string buscado){

	if (nodo!=NULL){

		if (strcmp(nodo->getTipoDato().c_str(),buscado.c_str())==0){encontrado=nodo;}

		else if (!nodo->obtenerLista()->empty()){
			list<Nodo*>::iterator it= nodo->obtenerLista()->begin();
			while(it!=nodo->obtenerLista()->end() && encontrado==NULL){
				buscarRecursivo(*it, encontrado, buscado);
				it++;
			}
		}
	}
}



void ArbolSintactico::cargarArbol(){

		ifstream archivo(this->pathYAML.c_str());

		int nroLinea = 0;

		if (archivo.is_open()){

			stack<Nodo*> pila;

			this->raiz=new Nodo("datos",nroLinea);
			pila.push(this->raiz);

			cargarArbolRecursivo(pila, archivo,nroLinea);

		    archivo.close();
		}

		this->normalizar();

		this->nodoActual=this->raiz;

}


/*
void ArbolSintactico::cargarArbolRecursivo(stack<Nodo*> pilaNodos, ifstream& archivo){

	if (!archivo.eof()){

		char* buffer=new char[255];

		archivo.getline(buffer,255,'\n');

		string str(buffer);

		str="  "+str;

		Nodo* nuevoNodo=new Nodo(str); //hay q normalizar despues. y agregar el caso de que haya mas de una raiz


		while( (this->existeShift(pilaNodos, nuevoNodo)==0) || (this->existeShift(pilaNodos, nuevoNodo)<0)){

			pilaNodos.pop();

		}

		if (this->existeShift(pilaNodos, nuevoNodo)>0) {
			//cout<<nuevoNodo->getDato()<<endl;
			pilaNodos.top()->agregarPtr(nuevoNodo);
			pilaNodos.push(nuevoNodo);
			cargarArbolRecursivo(pilaNodos,archivo);
		}

	}

}

*/
void ArbolSintactico::cargarArbolRecursivo(stack<Nodo*> pilaNodos, ifstream& archivo,int & numLinea){

	if (!archivo.eof()){
		numLinea++;

		char* buffer=new char[255];

		archivo.getline(buffer,255,'\n');

		string str(buffer);

		//agrego linea para hacer tratamiento a aquellas que no sigan el estandar YAML.
		chequearPalabra(str,pilaNodos.top()->getDato());

		str="  "+str;

		Nodo* nuevoNodo=new Nodo(str,numLinea); //hay q normalizar despues. y agregar el caso de que haya mas de una raiz


		while( (this->existeShift(pilaNodos, nuevoNodo)==0 ) || (this->existeShift(pilaNodos, nuevoNodo)<0)){

			pilaNodos.pop();

		}

		if (this->existeShift(pilaNodos, nuevoNodo)>0 ) {

			pilaNodos.top()->agregarPtr(nuevoNodo);
			pilaNodos.push(nuevoNodo);
			cargarArbolRecursivo(pilaNodos,archivo,numLinea);
		}

	}

}


void ArbolSintactico::normalizar(){

	Nodo* nodo=raiz;

	stack<Nodo*> pila;

	this->normalizarRecursivo(nodo,pila);

}




void ArbolSintactico::normalizarRecursivo(Nodo* nodo, stack<Nodo*> pila){

	if (nodo==NULL){
		return;
	}

	else{
		nodo->normalizar();
		if (!nodo->obtenerLista()->empty()){
			pila.push(nodo);
			list<Nodo*>::iterator it= nodo->obtenerLista()->begin();
			while(it!=nodo->obtenerLista()->end()){
				normalizarRecursivo(*it,pila);
				it++;
			}
			pila.pop();
		}
		else {

			pila.pop();
		}
	}
}




int ArbolSintactico::existeShift(stack<Nodo*> pilaNodos, Nodo* nuevoNodo){

	string cadena2= nuevoNodo->getDato();

	string cadena1= pilaNodos.top()->getDato();


	int i1=0;
	int i2=i1;

	while ((cadena1[i1]==' ')){
		i1++;
	}
	while ((cadena2[i2]==' ')){
		i2++;
	}
	return (i2-i1);
}



void ArbolSintactico::imprimir(){
	this->raiz->imprimir();
}

Nodo* ArbolSintactico::getNodoActual(){
	return this->nodoActual;
}


bool ArbolSintactico::esVacio(string s){
	if (s.size()==0) return true;
	return false;
}

string ArbolSintactico::agregarBlancos(string s){
	string nueva="";
	for (unsigned int i = 0; i<s.length();i++){
		if (s[i]==' ') nueva.append(" ");
	}
	return nueva;
}

bool ArbolSintactico::tieneCaracteresInvalidos(string s){
	for (unsigned int i = 0; i<s.length();i++){
			if ((s[i]==':') || ((s[i]=='-') )) return false;
	}
	return true;
}

void ArbolSintactico::chequearPalabra(string &s, string padre){
	//caso 1 : linea vacia

	if (esVacio(s)){
		s = agregarBlancos(padre) + "-<vacio>";

		return;
	}

	//caso 2 : tiene caracteres no propios del yaml

	if (tieneCaracteresInvalidos(s)){
		s = agregarBlancos(padre) + "-<invalido>";

		return;
	}

}

void ArbolSintactico::detectorErrores(Logger* logger,Nodo* nodo, string rutaYAML){
	if (nodo==NULL){

		return;
	}
	else if (nodo->listaNodos.empty()){
		if (nodo->getDato().find("<vacio>")!=std::string::npos){
			logger->escribirLinea("Se encontro una linea en blanco. Esta no sera tenida en cuenta"
					,rutaYAML,nodo->getNumeroDeLinea());
		}
		else if (nodo->getDato().find("<invalido>")!=std::string::npos){
				logger->escribirLinea("Se encontro una linea invalida. Esta no sera tenida en cuenta"
						,rutaYAML,nodo->getNumeroDeLinea());
		}
	}
	else{
		list<Nodo*>::iterator it= nodo->listaNodos.begin();
		while(it!=nodo->listaNodos.end()){
			detectorErrores(logger,*it,rutaYAML);
			it++;
		}

	}

}



ArbolSintactico::~ArbolSintactico() {
	// TODO Auto-generated destructor stub
}


